#include "sdk.h"
#include "wx/wxprec.h"
#include "wx/wx.h"
#include "menuutils.h"

#pragma implementation "menuutils.h"

wxMenuBar* wxMenuCmd::m_pMenuBar = NULL;

int wxFindMenuItem( wxMenuBar *p, const wxString &str ) {
  int id = wxNOT_FOUND;
  for( int i = 0; i < ( int )p->GetMenuCount(); i++ ) {
    id = p->GetMenu( i )->FindItem( str );
    if( id != wxNOT_FOUND ) {
      break;
    }
  }
  return id;
}

int FindMenuDuplicateItems( wxMenu* pMenu, wxString& rStr, int& rCount ) {
  size_t itemKnt = pMenu->GetMenuItemCount();
  for( size_t j = 0; j < itemKnt; j++ ) {
    wxMenuItem* pMenuItem = pMenu->FindItemByPosition( j );
    if( pMenuItem->GetSubMenu() ) {
      FindMenuDuplicateItems( pMenuItem->GetSubMenu(), rStr, rCount );
    }
    if( pMenuItem->GetKind() == wxITEM_SEPARATOR ) {
      continue;
    }
    if( wxMenuCmd::IsNumericMenuItem( pMenuItem ) ) {
      continue;
    }
    wxString menuItemLabel = pMenuItem->GetLabel().Trim();
    if( rStr == pMenuItem->GetLabel().Trim() ) {
      rCount++;
    }
  }
  return rCount;
}

wxString GetFullMenuPath( int id ) {
  wxString fullMenuPath = wxEmptyString;
  wxMenuBar* pbar = wxMenuCmd::m_pMenuBar;
  wxMenu* pMenu = 0;
  wxMenuItem* pMenuItem = pbar->FindItem( id, &pMenu );
  if( pMenuItem == NULL ) {
    return fullMenuPath;
  }
  fullMenuPath = pMenuItem->GetLabel().Trim();
  wxMenu* pParentMenu = pMenu->GetParent();
  while( pParentMenu ) {
    for( int i = 0; i < ( int )pParentMenu->GetMenuItemCount(); i++ ) {
      wxMenuItem* pitem = pParentMenu->GetMenuItems().Item( i )->GetData();
      if( pitem->GetSubMenu() && ( pitem->GetSubMenu() == pMenu ) ) {
        fullMenuPath.Prepend( pitem->GetLabel().Trim() + wxT( "\\" ) );
        break;
      }
    }
    pMenu = pParentMenu;
    pParentMenu = pParentMenu->GetParent();
  }
  for( int i = 0; i < ( int )pbar->GetMenuCount() ; ++i ) {
    wxMenu* pBarMenu = pbar->GetMenu( i );
    if( pBarMenu == pMenu ) {
      fullMenuPath.Prepend( pbar->GetLabelTop( i ) + wxT( "\\" ) );
    }
  }
  return fullMenuPath;
}

namespace {
  int FindMenuIdUsingFullMenuPath( const wxString& sFullMenuPath ) {
    if( sFullMenuPath.IsEmpty() ) {
      return wxNOT_FOUND;
    }
    wxMenuBar* pMenuBar = wxMenuCmd::m_pMenuBar;
    int id = wxNOT_FOUND;
    int menuIndex = wxNOT_FOUND;
    wxString fullMenuPath = sFullMenuPath;
    int levelCount = fullMenuPath.Freq( wxT( '\\' ) ) + 1;
    wxArrayString levels;
    for( int i = 0; i < levelCount; ++i ) {
      levels.Add( fullMenuPath.BeforeFirst( wxT( '\\' ) ) );
      fullMenuPath.Remove( 0, levels[i].Length() + 1 );
      levels[i].Trim();
    }
    if( wxNOT_FOUND == ( menuIndex = pMenuBar->FindMenu( levels[0] ) ) ) {
      return wxNOT_FOUND;
    }
    wxMenu* pMenu = pMenuBar->GetMenu( menuIndex );
    wxMenuItem* pMenuItem = 0;
    bool found = false;
    for( int i = 1; i < ( int )levels.GetCount(); ++i ) {
      if( not pMenu ) {
        return wxNOT_FOUND;
      }
      found = false;
      for( int j = 0; j < ( int )pMenu->GetMenuItemCount(); ++j ) {
        pMenuItem = pMenu->FindItemByPosition( j );
        if( pMenuItem->GetLabel().Trim() == levels[i] ) {
          menuIndex = j;
          pMenu = pMenuItem->GetSubMenu();
          found = true;
          break;
        }
      }
      if( found ) {
        continue;
      } else
      { return wxNOT_FOUND; }
    }
    if( found ) {
      id = pMenuItem->GetId();
    } else
    { id = wxNOT_FOUND; }
    return id;
  }
}

void wxMenuCmd::Update( wxMenuItem* pSpecificMenuItem ) {
  wxMenuItem* pLclMnuItem = m_pItem;
  if( pSpecificMenuItem ) {
    pLclMnuItem = pSpecificMenuItem;
  }
  if( not pSpecificMenuItem )
    if( m_pMenuBar->FindItem( m_nId ) != pLclMnuItem ) {
      return;
    }
  if( IsNumericMenuItem( pLclMnuItem ) ) {
    return;
  }
  wxString strText = pLclMnuItem->GetText();
  wxString str = strText.BeforeFirst( '\t' );
  int idx = 0;
  if( -1 != ( idx = str.Find( '_' ) ) ) {
    str[idx] = '&';
  }
  for( size_t i = 0; i < str.Length(); ++i )
    if( str[i] == '_' ) {
      str[i] = ' ';
    }
  str.Trim();
  if( m_nShortcuts <= 0 ) {
    pLclMnuItem->SetText( str );
    return;
  }
  wxString newtext = str + wxT( "\t" ) + GetShortcut( 0 )->GetStr();
  pLclMnuItem->SetText( newtext );
}

bool wxMenuCmd::IsNumericMenuItem( wxMenuItem* pwxMenuItem ) {
  wxString str = pwxMenuItem->GetText();
  if( str.Length() < 2 ) {
    return false;
  }
  if( str.Left( 1 ).IsNumber() ) {
    return true;
  }
  if( ( str[0] == '&' ) && ( str.Mid( 1, 1 ).IsNumber() ) ) {
    return true;
  }
  if( ( str[0] == '_' ) && ( str.Mid( 1, 1 ).IsNumber() ) ) {
    return true;
  }
  return false;
}

void wxMenuCmd::Exec( wxObject *origin, wxEvtHandler *client ) {
  wxCommandEvent menuEvent( wxEVT_COMMAND_MENU_SELECTED, GetId() );
  wxASSERT_MSG( client, wxT( "An empty client handler ?!?" ) );
  menuEvent.SetEventObject( origin );
  client->ProcessEvent( menuEvent );
}

wxCmd *wxMenuCmd::CreateNew( wxString sCmdName, int id ) {
  if( !m_pMenuBar ) {
    return NULL;
  }
  wxMenuItem* pMenuItem = 0;
  wxString fullMenuPath = sCmdName;
  wxString cmdName = fullMenuPath.AfterLast( wxT( '\\' ) );
  cmdName.Trim();
  int actualMenuID = id;
  wxMenuItem* pMenuItemByCfgId = m_pMenuBar->FindItem( id );
  if( pMenuItemByCfgId && ( pMenuItemByCfgId->GetLabel().Trim() == cmdName ) ) {
    pMenuItem = pMenuItemByCfgId;
  } else {
    actualMenuID = FindMenuIdUsingFullMenuPath( fullMenuPath ) ;
    if( not( wxNOT_FOUND == actualMenuID ) ) {
      pMenuItem = m_pMenuBar->FindItem( actualMenuID );
    }
  }
  if( not pMenuItem ) {
    return NULL;
  }
  return new wxMenuCmd( pMenuItem );
}

bool wxMenuWalker::IsNumericMenuItem( wxMenuItem* pwxMenuItem ) {
  wxString str = pwxMenuItem->GetText();
  if( str.Length() < 2 ) {
    return false;
  }
  if( str.Left( 1 ).IsNumber() ) {
    return true;
  }
  if( ( str[0] == '&' ) && ( str.Mid( 1, 1 ).IsNumber() ) ) {
    return true;
  }
  if( ( str[0] == '_' ) && ( str.Mid( 1, 1 ).IsNumber() ) ) {
    return true;
  }
  return false;
}

void wxMenuWalker::WalkMenuItem( wxMenuBar* p, wxMenuItem* m, void* data ) {
  if( IsNumericMenuItem( m ) ) {
    return;
  }
  void* tmp = OnMenuItemWalk( p, m, data );
  if( m->GetSubMenu() ) {
    m_nLevel++;
    WalkMenu( p, m->GetSubMenu(), tmp );
    OnMenuExit( p, m->GetSubMenu(), tmp );
    m_nLevel--;
  }
  DeleteData( tmp );
}

void wxMenuWalker::WalkMenu( wxMenuBar* p, wxMenu* m, void* data ) {
  for( int i = 0; i < ( int )m->GetMenuItemCount(); i++ ) {
    wxMenuItem* pitem = m->GetMenuItems().Item( i )->GetData();
    void* tmp = OnMenuWalk( p, m, data );
    if( pitem->GetKind() != wxITEM_SEPARATOR && pitem->GetLabel().Trim() != wxEmptyString ) {
      WalkMenuItem( p, pitem, tmp );
    }
    DeleteData( tmp );
  }
  OnMenuExit( p, m, data );
}

void wxMenuWalker::Walk( wxMenuBar *p, void *data ) {
  wxASSERT( p );
  for( int i = 0; i < ( int )p->GetMenuCount(); i++ ) {
    wxMenu *m = p->GetMenu( i );
    m_nLevel++;
    void* tmp = OnMenuWalk( p, m, data );
    WalkMenu( p, m, tmp );
    m_nLevel--;
    DeleteData( tmp );
  }
}

void wxMenuTreeWalker::FillTreeBranch( wxMenuBar *p, wxTreeCtrl *ctrl, wxTreeItemId branch ) {
  m_root = branch;
  m_pTreeCtrl = ctrl;
  m_pTreeCtrl->DeleteChildren( branch );
  Walk( p, &branch );
}

void* wxMenuTreeWalker::OnMenuWalk( wxMenuBar *p, wxMenu *m, void *data ) {
  wxTreeItemId* id = ( wxTreeItemId * )data;
  int i;
  if( !id->IsOk() ) {
    return NULL;
  }
  if( *id == m_root ) {
    for( i = 0; i < ( int )p->GetMenuCount(); i++ )
      if( p->GetMenu( i ) == m ) {
        break;
      }
    wxASSERT( i != ( int )p->GetMenuCount() );
    wxTreeItemId newId = m_pTreeCtrl->AppendItem( *id, wxMenuItem::GetLabelFromText( p->GetLabelTop( i ) ) );
    return new wxTreeItemId( newId );
  }
  return new wxTreeItemId( *id );
}

void* wxMenuTreeWalker::OnMenuItemWalk( wxMenuBar *, wxMenuItem *m, void *data ) {
  wxTreeItemId* id = ( wxTreeItemId * )data;
  if( id->IsOk() ) {
    wxExTreeItemData* treedata = new wxExTreeItemData( m->GetId() );
    wxTreeItemId newId = m_pTreeCtrl->AppendItem( *id, m->GetLabel().Trim(), -1, -1, treedata );
    return new wxTreeItemId( newId );
  }
  return NULL;
}

void wxMenuTreeWalker::DeleteData( void *data ) {
  wxTreeItemId* p = ( wxTreeItemId * )data;
  if( p ) {
    delete p;
  }
}

void wxMenuComboListWalker::FillComboListCtrl( wxMenuBar *p, wxComboBox *combo ) {
  m_pCategories = combo;
  m_pCategories->Clear();
  Walk( p, NULL );
}

void *wxMenuComboListWalker::OnMenuWalk( wxMenuBar *p, wxMenu *m, void * ) {
  wxString toadd;
  if( m_strAcc.IsEmpty() ) {
    int i;
    for( i = 0; i < ( int )p->GetMenuCount(); i++ )
      if( p->GetMenu( i ) == m ) {
        break;
      }
    wxASSERT( i != ( int )p->GetMenuCount() );
    toadd = wxMenuItem::GetLabelFromText( p->GetLabelTop( i ) );
    m_strAcc = toadd;
  } else {
    toadd = m_strAcc;
  }
  int found;
  if( ( found = m_pCategories->FindString( toadd ) ) != wxNOT_FOUND ) {
    return m_pCategories->GetClientObject( found );
  }
  wxClientData* cd = new wxExComboItemData();
  m_pCategories->Append( toadd, cd );
  return cd;
}

void *wxMenuComboListWalker::OnMenuItemWalk( wxMenuBar *, wxMenuItem *m, void *data ) {
  wxExComboItemData *p = ( wxExComboItemData * )data;
  if( m->GetSubMenu() == NULL ) {
    p->Append( m->GetLabel().Trim(), m->GetId() );
  } else {
    m_strAcc += wxT( " | " ) + m->GetLabel().Trim();
  }
  return NULL;
}

void wxMenuComboListWalker::OnMenuExit( wxMenuBar *, wxMenu *, void * ) {
  if( !m_strAcc.IsEmpty() ) {
    int diff = m_strAcc.Find( wxT( '|' ), TRUE );
    if( diff == wxNOT_FOUND ) {
      m_strAcc = wxEmptyString;
    } else
    { m_strAcc = m_strAcc.Left( diff ); }
    m_strAcc.Trim();
  }
}

void wxMenuComboListWalker::DeleteData( void * ) {
}

void *wxMenuShortcutWalker::OnMenuItemWalk( wxMenuBar *, wxMenuItem *m, void * ) {
  wxASSERT( m );
  wxCmd *cmd = new wxMenuCmd( m, m->GetLabel().Trim(), m->GetHelp() );
  m_pArr->Add( cmd );
  wxAcceleratorEntry* a = m->GetAccel();
  if( a ) {
    cmd->AddShortcut( a->GetFlags(), a->GetKeyCode() );
  }
  if( a ) {
    delete a;
  }
  return NULL;
}

void wxMenuShortcutWalker::DeleteData( void *ndata ) {
  wxASSERT_MSG( data == NULL,  wxT( "wxMenuShortcutWalker does not use the 'data' parameter" ) );
}
